import {v4 as uuid} from "uuid";
/**
 Created by:
 muhtearjan mehmood مۇختەرجان مەخمۇت (Email: yeganaaa@163.com)
 At 2020-01-12 12:02 چۈشتىن بۇرۇن
 */


export interface IValidatable {
    validate(): boolean
}

export abstract class EntityBase<T extends EntityBase<any>> {
    _id: string = uuid()
    createdAt: Date = new Date()
    updatedAt: Date = new Date()

    public copyFrom(obj: T): T {
        for (let prop in this) {
            let valid = true
            const value = (obj as any)[prop]
            if (value == null) continue
            const type = typeof ((this as any)[prop])
            const propObj = this[prop] as any
            valid = valid && propObj != null
            let copyMethod = null
            if (valid) copyMethod = propObj["copyFrom"]
            valid = valid && type == "object"
            valid = valid && copyMethod != null
            if (valid) {
                (this[prop] as any as EntityBase<T>).copyFrom(value)
            } else {
                valid = true
                valid = valid && type == "object"
                valid = valid && (prop == "createdAt" || prop == "updatedAt")
                if (valid)
                    this[prop] = new Date(value.toString()) as any
                else
                    this[prop] = value
            }
        }
        return this as any
    }

    public prepareForUpdate(): T {
        const updateProperty = this["updatedAt"]
        if (updateProperty != null) this["updatedAt"] = new Date()
        for (let prop in this) {
            const prepareMethod = (this[prop] as any)["prepareForUpdate"]
            if (prepareMethod != null) {
                prepareMethod.bind(this[prop])()
            }
        }
        return this as any
    }

    public copyIdFrom(entity: T): T {
        this["_id"] = entity._id
        for (let prop in this) {
            const copyIdMethod = (this[prop] as any)["copyIdFrom"] as (entity: any) => any
            if (copyIdMethod != null) {
                copyIdMethod.bind(this[prop])((entity as any)[prop])
            }
        }
        return this as any
    }
}
